<?php

namespace common\service;


use common\model\EntityModel;
use common\model\ProjectTemplateModel;
use common\model\StepCategoryModel;
use support\SingletonTrait;
use think\module\Module;

/**
 * 实体下游服务
 */
class EntityDownstreamService
{
    // 单例工具
    use SingletonTrait;

    /**
     * 查询下游实体列表
     * @param $entityId
     * @param bool $crossShotAsset
     * @return array
     */
    public function getDownstreamEntityList($entityId, $crossShotAsset = true): array
    {
        $entity = model(EntityModel::class)->find($entityId);
        $entityStepCategory = model(StepCategoryModel::class)->where(['entity_id' => $entity['module_id']])->find();
        $relatedEntities = [];
        // 特殊处理 镜头属于序列的上游
        if ($entity['module_id'] === Module::$moduleDictData['module_index_by_code']['sequence']['id']) {
            $shotList = model(EntityModel::class)->where(['entity_id' => $entity['id']])->field('id')->select();
            if (!empty($shotList)) {
                $relatedEntities = array_merge($relatedEntities, array_column($shotList, 'id'));
            }
        }
        $projectTemplate = model(ProjectTemplateModel::class)
            ->join("project ON project.project_template_id = project_template.id")
            ->where([
                'project.id' => $entity['project_id'],
            ])
            ->field("project_template.step_category_dependency")
            ->find();
        if (empty($projectTemplate)) {
            return $relatedEntities;
        }
        $stepCategoryDependency = json_decode($projectTemplate['step_category_dependency'], true);
        /**
         * 没有 一级分类关系配置 直接返回true
         */
        if (!isset($stepCategoryDependency['edges']) || empty($stepCategoryDependency['edges'])) {
            return $relatedEntities;
        }
        $targets = [];
        foreach ($stepCategoryDependency['edges'] as $edge) {
            if ($edge['source'] == $entityStepCategory['id']) {
                $targets[] = $edge['target'];
            }
        }

        if (!empty($targets)) {
            /**
             * 下游
             */
            $targetStepCategories = model(StepCategoryModel::class)
                ->where(['id' => ['IN', implode(',', $targets)]])
                ->select();
            $entityModule = Module::$moduleDictData['module_index_by_id'][$entity['module_id']];
            $entity['json'] = json_decode($entity['json'], true);
            $moduleCode = $entityModule['code'];
            $filter = '';
            foreach ($targetStepCategories as $sourceStepCategory) {

                $currentModuleId = Module::$moduleDictData['module_index_by_code'][$sourceStepCategory['code']]['id'];

                if ($crossShotAsset === false
                    && (in_array($moduleCode, ['asset', 'design', 'level']) && in_array($sourceStepCategory['code'], ['storyboard', 'sequence', 'shot'])
                        || in_array($moduleCode, ['storyboard', 'sequence', 'shot']) && in_array($sourceStepCategory['code'], ['asset', 'design', 'level']))
                ) {
                    continue;
                }

                // 查询关联我的资产
                $filter .= " (module_id = {$currentModuleId} AND FIND_IN_SET({$entityId},JSON_UNQUOTE(JSON_EXTRACT(json,'$.{$sourceStepCategory['code']}_{$moduleCode}')))) OR";
            }
            if (!empty($filter)) {
                $filter = rtrim($filter, 'OR');
                $entityList = model(EntityModel::class)->where(['project_id' => $entity['project_id']])->where($filter)->field('id')->select();
                if (!empty($entityList)) {
                    $relatedEntities = array_merge($relatedEntities, array_column($entityList, 'id'));
                }
            }
        }
        return $relatedEntities;
    }

    /**
     * 查询上游实体列表 通过关联关系获取
     * @param $entityIdList
     * @param bool $crossShotAsset
     * @return array
     */
    public function getDownstreamEntityListBatch($entityIdList, $crossShotAsset = true): array
    {
        $res = model(EntityModel::class)->where(['id' => ['IN', implode(',', $entityIdList)]])->select();
        // 实体不存在那么 返回空数组
        if (empty($res)) {
            return [];
        }
        $projectId = $res[0]['project_id'];
        $projectTemplate = model(ProjectTemplateModel::class)
            ->join("project ON project.project_template_id = project_template.id")
            ->where([
                'project.id' => $projectId,
            ])
            ->field("project_template.step_category_dependency")
            ->cache(C('database.default_query_cache_time'))
            ->find();
        $edges = [];
        if (!empty($projectTemplate)) {
            $stepCategoryDependency = json_decode($projectTemplate['step_category_dependency'], true);
            $edges = $stepCategoryDependency['edges'] ?? [];
        }
        $stepCategoryList = StepCategoryService::getInstance()->getList([], '*');

        $entityStepCategoryList = array_column(array_filter($stepCategoryList, function ($i) {
            return $i['parent_id'] == 0;
        }), null, 'entity_id');
        $stepCategoryMap = array_column($stepCategoryList, null, 'id');
        $edgesGrouped = [];
        foreach ($edges as $sourceStepCategory) {
            if (isset($stepCategoryMap[$sourceStepCategory['source']])) {
                $edgesGrouped[$sourceStepCategory['source']][] = $stepCategoryMap[$sourceStepCategory['target']];
            }
        }
        $res = array_column($res, null, 'id');

        $sequenceIdList = [];
        $filter = [];
        $relationFields = [];
        foreach ($res as &$entity) {
            $entityModule = module_by_id($entity['module_id']);
            $entity['downstream_entity_list'] = [];
            $entity['relate_data_map'] = [];
            if ($entityModule['code'] == 'sequence') {
                $sequenceIdList[] = $entity['id'];
                $relationFields['entity_id'] = 'entity_id';
            }
            // 实体模块找不到分类
            if (empty($entityStepCategoryList[$entity['module_id']])) {
                continue;
            }
            $entity['json'] = json_decode($entity['json'], true);
            $entity = array_merge($entity, $entity['json']);
            unset($entity['json']);
            $entityStepCategory = $entityStepCategoryList[$entity['module_id']];
            // 项目模板没有配置下游relation
            if (empty($edgesGrouped[$entityStepCategory['id']])) {
                continue;
            }
            foreach ($edgesGrouped[$entityStepCategory['id']] as $sourceStepCategory) {

                $currentModuleId = module_by_code($sourceStepCategory['code'])['id'];

                if ($crossShotAsset === false
                    && (in_array($entityModule['code'], ['asset', 'design', 'level']) && in_array($sourceStepCategory['code'], ['storyboard', 'sequence', 'shot'])
                        || in_array($entityModule['code'], ['storyboard', 'sequence', 'shot']) && in_array($sourceStepCategory['code'], ['asset', 'design', 'level']))
                ) {
                    continue;
                }

                $field = "{$sourceStepCategory['code']}_{$entityModule['code']}";

                $filter[] = [
                    'module_id' => $currentModuleId,
                    "json->>'$.{$field}'" => ['FIND_IN_SET', $entity['id']],
                ];
                $entity['relate_data_map'][] = [
                    'field' => $field,
                    'data' => $entity['id'],
                ];
                $relationFields[$field] = $field;
            }
        }

        if (empty($filter)) {
            return $res;
        }
        if (!empty($sequenceIdList)) {
            $filter[] = [
                'entity_id' => $sequenceIdList,
            ];
        }

        if (count($filter) >= 1) {
            $filter['_logic'] = 'OR';
            $filter = [$filter];
        }
        $downstreamEntityList = model(EntityModel::class)->where(['project_id' => $projectId])->where($filter)->select();
        $downstreamEntityRelationMap = [];
        foreach ($downstreamEntityList as $downstreamEntityIndex => &$downstreamEntity) {
            $downstreamEntity['json'] = json_decode($downstreamEntity['json'], true);
            $downstreamEntity = array_merge($downstreamEntity, $downstreamEntity['json']);
            unset($downstreamEntity['json']);
            foreach ($relationFields as $relationField) {
                $relationData = $downstreamEntity[$relationField] ?? '';
                foreach (explode(',', $relationData) as $relateDataItem) {
                    $relateDataItem = intval($relateDataItem);
                    $downstreamEntityRelationMap[$relationField][$relateDataItem][$downstreamEntity['id']] = &$downstreamEntityList[$downstreamEntityIndex];
                }
            }
        }

        unset($entity);
        foreach ($res as &$entity) {
            $entityDownstreamEntityList = [];
            foreach ($entity['relate_data_map'] as $entityRelationDataMap) {
                if (empty($downstreamEntityRelationMap[$entityRelationDataMap['field']][$entityRelationDataMap['data']])) {
                    continue;
                }
                $entityDownstreamEntityList += $downstreamEntityRelationMap[$entityRelationDataMap['field']][$entityRelationDataMap['data']];
            }
            $entity['downstream_entity_list'] = $entityDownstreamEntityList;
        }
        return $res;
    }
}
